﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Diagnostics;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// Convert类型扩展方法类
    /// </summary>
    public static partial class ConvertEx
    {

        #region Base64编码-解码
        /// <summary>
        /// bytes编码成Base64字符串
        /// </summary>
        /// <param name="buffer">要编码的bytes</param>
        /// <returns>Base64字符串</returns>
        public static string EncodingBase64Buffer(byte[] buffer)
        {
            return Convert.ToBase64String(buffer);
        }

        /// <summary>
        /// Base64字符串解码成bytes
        /// </summary>
        /// <param name="base64Text">要解码的Base64文本</param>
        /// <returns>bytes</returns>
        public static byte[] DecodeBase64Buffer(string base64Text)
        {
            return Convert.FromBase64String(base64Text);
        }


        /// <summary>
        /// 文本编码成Base64字符串
        /// </summary>
        /// <param name="text">要编码的文本</param>
        /// <returns>Base64字符串</returns>
        public static string EncodingBase64(string text)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(text);
            return Convert.ToBase64String(buffer);
        }

        /// <summary>
        /// Base64字符串解码成原始文本
        /// </summary>
        /// <param name="base64Text">要解码的Base64文本</param>
        /// <returns>原始文本</returns>
        public static string DecodeBase64(string base64Text)
        {
            byte[] buffer = Convert.FromBase64String(base64Text);
            return Encoding.UTF8.GetString(buffer);
        }

        #endregion



        /// <summary>
        /// 数值类型数据转换为百分比字符串
        /// </summary>
        /// <typeparam name="T">具体的某种整形值类型</typeparam>
        /// <param name="value">十进制整形数值</param>
        /// <param name="digits">百分比保留的小数点位数</param>
        /// <returns>百分比字符串</returns>
        public static string ToPersentString<T>(this T value, int digits) where T : struct, IFormattable, IConvertible
        {
            decimal dvalue;
            if (!decimal.TryParse(value.ToString(), out dvalue))
            {
                throw new Exception(string.Format("值:{0}不是有效的数值类型数据", value));
            }

            dvalue = dvalue * 100;
            string str = dvalue.ToString();
            if (str.Contains("."))
            {
                int pLocation = str.LastIndexOf('.');
                if (digits > 0)
                {
                    int subLength = pLocation + digits + 1;
                    if (str.Length >= subLength)
                    {
                        str = str.Substring(0, subLength);
                    }
                    else
                    {
                        int appendCount = digits - (str.Length - pLocation - 1);
                        StringBuilder sb = new StringBuilder();
                        sb.Append(str);
                        sb.Append('0', appendCount);
                        str = sb.ToString();
                    }
                }
                else
                {
                    str = str = str.Substring(0, pLocation);
                }
            }
            else
            {
                if (digits > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append(str);
                    sb.Append('.');
                    sb.Append('0', digits);
                    str = sb.ToString();
                }
            }

            return string.Format("{0}%", str);
        }

        /// <summary>
        /// 转换字节数为GB字符串
        /// </summary>
        /// <param name="value">字节数</param>
        /// <returns>GB字符串</returns>
        public static string ToGBString<T>(this T value) where T : struct, IFormattable, IConvertible
        {
            float size;
            if (!float.TryParse(value.ToString(), out size))
            {
                throw new Exception(string.Format("值:{0}不是有效的数值类型数据", value));
            }

            if (size < 0)
            {
                throw new Exception(string.Format("值:{0}不能是负值", size));
            }

            float gbSize = (float)size / 1024 / 1024 / 1024;
            if (gbSize - (int)gbSize > 0)
            {
                gbSize = gbSize * 100;
                gbSize = (float)((int)gbSize) / 100;
            }
            return string.Format("{0}GB", gbSize);
        }




        #region 有符号数数据数组 与 无符号数据数组 相互转换

        private const Int16 _DIF_VALUE_16 = 128;
        private const Int32 _DIF_VALUE_32 = 32768;
        private const Int64 _DIF_VALUE_64 = 2147483648L;

        #region 有符号数数据数组转换为无符号数据数组

        /// <summary>
        /// 将sbyte[]转换为byte[]
        /// </summary>
        /// <param name="buffer">sbyte[]</param>
        /// <returns>byte[]</returns>
        public static byte[] ToUnsigned(sbyte[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new byte[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (byte)((Int16)buffer[i] + _DIF_VALUE_16);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将Int16[]转换为UInt16[]
        /// </summary>
        /// <param name="buffer">Int16[]</param>
        /// <returns>UInt16[]</returns>
        public static UInt16[] ToUnsigned(Int16[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new UInt16[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (UInt16)((Int32)buffer[i] + _DIF_VALUE_32);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将Int32[]转换为UInt32[]
        /// </summary>
        /// <param name="buffer">Int32[]</param>
        /// <returns>UInt32[]</returns>
        public static UInt32[] ToUnsigned(Int32[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new UInt32[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (UInt32)((Int64)buffer[i] + _DIF_VALUE_64);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将有符号数组转换为无符号数组
        /// </summary>
        /// <typeparam name="T">目标有符号数组元素类型.仅支持sbyte、Int16、Int32，其它类型将抛出不支持异常</typeparam>
        /// <param name="signedBuffer">有符号数组</param>
        /// <returns>无符号数组</returns>
        /// <exception cref="NotSupportedException"></exception>
        public static object ToUnsigned<T>(T[] signedBuffer) where T : struct, IConvertible, IComparable
        {
            if (signedBuffer == null)
            {
                return null;
            }

            TypeCode typeCode = Type.GetTypeCode(typeof(T));
            object result;
            switch (typeCode)
            {
                case TypeCode.Byte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                    result = signedBuffer;
                    break;
                case TypeCode.SByte:
                    result = ToUnsigned(signedBuffer as sbyte[]);
                    break;
                case TypeCode.Int16:
                    result = ToUnsigned(signedBuffer as Int16[]);
                    break;
                case TypeCode.Int32:
                    result = ToUnsigned(signedBuffer as Int32[]);
                    break;
                case TypeCode.Char:
                case TypeCode.UInt64:
                case TypeCode.Int64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                default:
                    throw new NotSupportedException(typeof(T).ToString());
            }

            return result;
        }

        #endregion

        #region 无符号数据数组转换为有符号数数据数组

        /// <summary>
        /// 将byte[]转换为sbyte[]
        /// </summary>
        /// <param name="buffer">byte[]</param>
        /// <returns>sbyte[]</returns>
        public static sbyte[] ToSigned(byte[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new sbyte[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (sbyte)((Int16)buffer[i] - _DIF_VALUE_16);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将UInt16[]转换为Int16[]
        /// </summary>
        /// <param name="buffer">UInt16[]</param>
        /// <returns>Int16[]</returns>
        public static Int16[] ToSigned(UInt16[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new Int16[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (Int16)((Int32)buffer[i] - _DIF_VALUE_32);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将UInt32[]转换为Int32[]
        /// </summary>
        /// <param name="buffer">UInt32[]</param>
        /// <returns>Int32[]</returns>
        public static Int32[] ToSigned(UInt32[] buffer)
        {
            if (buffer == null)
            {
                return null;
            }

            var retBuffer = new Int32[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                retBuffer[i] = (Int32)((Int64)buffer[i] - _DIF_VALUE_64);
            }

            return retBuffer;
        }

        /// <summary>
        /// 将无符号数组转换为有符号数组
        /// </summary>
        /// <typeparam name="T">原始无符号数组元素类型.仅支持byte、UInt16、UInt32，其它类型将抛出不支持异常</typeparam>
        /// <param name="unsignedBuffer">无符号数组</param>
        /// <returns>有符号数组</returns>
        /// <exception cref="NotSupportedException">不支持的数据类型，将抛出不支持异常</exception>
        public static object ToSigned<T>(T[] unsignedBuffer) where T : struct, IConvertible, IComparable
        {
            if (unsignedBuffer == null)
            {
                return null;
            }

            TypeCode typeCode = Type.GetTypeCode(typeof(T));
            object result;
            switch (typeCode)
            {
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                    result = unsignedBuffer;
                    break;
                case TypeCode.Byte:
                    result = ToSigned(unsignedBuffer as byte[]);
                    break;
                case TypeCode.UInt16:
                    result = ToSigned(unsignedBuffer as UInt16[]);
                    break;
                case TypeCode.UInt32:
                    result = ToSigned(unsignedBuffer as UInt32[]);
                    break;
                case TypeCode.Char:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                default:
                    throw new NotSupportedException(typeof(T).ToString());
            }

            return result;
        }

        #endregion

        #endregion


    }
}
